#pragma once
#include <iostream>
#include <queue>
#include <pthread.h>
#include "Cond.hpp"
#include "Mutex.hpp"

namespace BlockQueueModule
{
    using namespace LockModule;
    using namespace CondModule;

    static const int gcap = 10;

    template<class T>
    class BlockQueue
    {
    private:
        bool IsFull()
        {
            return _q.size()==_cap;
        }
        bool IsEmpty()
        {
            return _q.empty();
        }
    public:
        BlockQueue(int cap = gcap):_cap(cap)
        {}
        void Equeue(const T& in)//生产者
        {
            LockGuard lockguard(_mutex);
            while(IsFull())//对条件进行判断防止伪唤醒
            {
                std::cout<<"生产者进入等待..."<<std::endl;
                _pwait_num++;
                _productor_cond.Wait(_mutex);
                _pwait_num--;
                std::cout<<"生产者被唤醒"<<std::endl;
            }
            _q.push(in);//
            if(_cwait_num)
            {
                std::cout<<"叫醒消费者"<<std::endl;
                _consumer_cond.Notify();
            }

        }
        void Pop(T* out)//消费者
        {
            LockGuard lockguard(_mutex);
            while(IsEmpty())
            {
                std::cout<<"消费者进入等待..."<<std::endl;
                _cwait_num++;
                _consumer_cond.Wait(_mutex);
                _cwait_num--;
                std::cout<<"消费者被唤醒..."<<std::endl;
            }
            *out = _q.front();
            _q.pop();
            if(_pwait_num)
            {
                std::cout<<"叫醒生产者"<<std::endl;
                _productor_cond.Notify();
            }
        }
    private:
        std::queue<T> _q;
        int _cap;   //bq的最大容量
        Mutex _mutex;
        Cond _productor_cond; //生产者条件变量
        Cond _consumer_cond; //消费者条件变量

        int _cwait_num= 0;
        int _pwait_num=0;
    };
}